﻿using System;
using System.Collections.Generic;
using System.Linq;
using Validity.Contexts;
using Validity.Localization;
using Validity.Rules;

namespace Validity
{
  public static class IsNotInDomainConstraint
  {
    public static IConditionalValidationContext<TObject, TValue> IsNotInDomain<TObject, TValue>(this IValidationContext<TObject, TValue> context, params TValue[] domain)
    {
      Verify.NotNull(domain);
      return context.IsNotInDomain(obj => domain);
    }

    public static IConditionalValidationContext<TObject, TValue> IsNotInDomain<TObject, TValue>(this IValidationContext<TObject, TValue> context, IEnumerable<TValue> domain)
    {
      Verify.NotNull(domain);
      return context.IsNotInDomain(obj => domain);
    }

    public static IConditionalValidationContext<TObject, TValue> IsNotInDomain<TObject, TValue>(this IValidationContext<TObject, TValue> context, Func<IEnumerable<TValue>> domainRetriever)
    {
      Verify.NotNull(domainRetriever);
      return context.IsNotInDomain(obj => domainRetriever.Invoke());
    }

    public static IConditionalValidationContext<TObject, TValue> IsNotInDomain<TObject, TValue>(this IValidationContext<TObject, TValue> context, Func<TObject, IEnumerable<TValue>> domainRetriever)
    {
      Verify.NotNull(domainRetriever);

      context.AddRule(new Rule<TObject, TValue>(
        (obj, val) => !(domainRetriever.Invoke(obj) ?? new TValue[0]).Where(item => Equals(item, val)).Any(),
        (obj, val) => String.Format(RuleViolations.DomainIntersect, val)
      ));

      return new ConditionalValidationContext<TObject, TValue>(context);
    }
  }
}
